package com.noble.meether.chat.ui.agora.util;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.view.SurfaceView;

import com.noble.glamour.module.logic.application.App;
import com.noble.glamour.module.logic.application.ModuleMgr;
import com.noble.library.log.PToast;
import com.noble.meether.R;
import com.noble.meether.chat.ui.agora.model.AgoraConstant;
import com.noble.meether.chat.ui.agora.model.EngineConfig;

import io.agora.rtc.Constants;
import io.agora.rtc.RtcEngine;
import io.agora.rtc.video.VideoCanvas;

/**
 * 音视频通信SDK初始化等耗时工作放在该类执行: 在App启动时实例化
 * <p>
 * Created by Su on 2017/6/27.
 */
public class RtcWorkerThread extends Thread {
    private final Context mContext;

    private static final int ACTION_WORKER_THREAD_QUIT = 0X1010;  // 退出工作线程
    private static final int ACTION_WORKER_JOIN_CHANNEL = 0X2010; // 加入聊天频道
    private static final int ACTION_WORKER_LEAVE_CHANNEL = 0X2011;// 离开聊天频道
    private static final int ACTION_WORKER_CONFIG_ENGINE = 0X2012;// 配置引擎
    private static final int ACTION_WORKER_PREVIEW = 0X2014;      // 视频预览

    private WorkerThreadHandler mWorkerHandler;   // 工作线程处理Handler
    private boolean mReady;                       // 引擎是否初始化成功标志
    private RtcEngine mRtcEngine;                 // 引擎

    public RtcWorkerThread(Context context) {
        this.mContext = context;
    }

    // ========================== 工作线程初始化 ===========================

    /**
     * 等待线程启动完毕
     */
    public final void waitForReady() {
        while (!mReady) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void run() {
        Looper.prepare();
        mWorkerHandler = new WorkerThreadHandler(this);
        ensureRtcEngineReadyLock();
        mReady = true;
        Looper.loop();
    }

    // ================================== 引擎操作, 对外接口 =======================================

    // 获取引擎对象
    public RtcEngine getRtcEngine() {
        return ensureRtcEngineReadyLock();
    }

    /**
     * 加入频道
     */
    public final void joinChannel() {
        try {
            if (Thread.currentThread() != this) {
                Message envelop = new Message();
                envelop.what = ACTION_WORKER_JOIN_CHANNEL;
                mWorkerHandler.sendMessage(envelop);
                return;
            }

            // 处于工作线程
            ensureRtcEngineReadyLock();
            EngineConfig config = ModuleMgr.getRtcEnginMgr().getEngineConfig();
            mRtcEngine.joinChannel(config.mChannelKey, config.mChannel, "OpenVCall", 0);
        } catch (Exception e) {
            PToast.showShort(App.activity.getString(R.string.chat_join_fail_tips));
        }
    }

    /**
     * 离开频道
     */
    public final void leaveChannel(String channel) {
        if (mRtcEngine != null) {
            mRtcEngine.leaveChannel();
//            mRtcEngine.disableVideo();
//            mRtcEngine.disableAudio();
        }
    }

    /**
     * 视频配置:  未使用内置数据加密
     *
     * @param vProfile       视频属性：{@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#set-video-profile-setvideoprofile'}
     * @param encryptionKey  上行下行数据包加密密码key，互相通讯程序内需保持一致
     * @param encryptionMode 加密方案，{@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#id13'}
     */
    public final void configVideoEngine(int vProfile, String encryptionKey, String encryptionMode) {
        if (Thread.currentThread() != this) {
            Message envelop = new Message();
            envelop.what = ACTION_WORKER_CONFIG_ENGINE;
            envelop.obj = new Object[]{vProfile, encryptionKey, encryptionMode};
            mWorkerHandler.sendMessage(envelop);
            return;
        }

        ensureRtcEngineReadyLock();
        if (!TextUtils.isEmpty(encryptionKey)) {
            mRtcEngine.setEncryptionMode(encryptionMode);
            mRtcEngine.setEncryptionSecret(encryptionKey);
        }

        mRtcEngine.setVideoProfile(vProfile, false);
    }

    /**
     * 绑定已方视频容器， 开启视频预览
     *
     * @param start 是否开启视频
     * @param view  视频显示视窗容器
     * @param uid   本地用户ID，与 joinChannel() 方法中的 uid保持一致
     */
    public final void preview(boolean start, SurfaceView view, int uid) {
        if (Thread.currentThread() != this) {
            Message envelop = new Message();
            envelop.what = ACTION_WORKER_PREVIEW;
            envelop.obj = new Object[]{start, view, uid};
            mWorkerHandler.sendMessage(envelop);
            return;
        }

        ensureRtcEngineReadyLock();
        if (start) {
            mRtcEngine.setupLocalVideo(new VideoCanvas(view, VideoCanvas.RENDER_MODE_HIDDEN, uid));
            mRtcEngine.startPreview();
        } else {
            mRtcEngine.stopPreview();
        }
    }

    /**
     * 切换摄像头
     */
    public final void switchCamera() {
        ensureRtcEngineReadyLock();
        mRtcEngine.switchCamera();
    }

    /**
     * 切换话筒
     *
     * @param defaultToSpeaker true: 外放  false: 听筒
     *                         {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#set-default-audio-route-setdefaultaudioroutetospeakerphone'}
     */
    public final void switchMicro(boolean defaultToSpeaker) {
        ensureRtcEngineReadyLock();
        mRtcEngine.setDefaultAudioRoutetoSpeakerphone(defaultToSpeaker);
    }

    /**
     * 是否开启扬声器
     *
     * @param enabled true  加入频道前 ： 无论是否有耳机蓝牙，均从扬声器出声
     *                加入频道后：  无论之前语音是路由到耳机蓝牙还是听筒，均从扬声器出声
     *                false: 语音会根据默认路由出声
     */
    public final void setEnableSpeakephone(boolean enabled) {
        ensureRtcEngineReadyLock();
        mRtcEngine.setEnableSpeakerphone(enabled);
    }

    /**
     * 静音本地音频流
     *
     * @param muted true: 麦克风静音  false: 取消静音
     */
    public final void switchLocalAudioStream(boolean muted) {
        ensureRtcEngineReadyLock();
        mRtcEngine.muteLocalAudioStream(muted);
    }

    /**
     * 资源释放
     */
    public final void release() {
        RtcEngine.destroy();
        mRtcEngine = null;
    }

    /**
     * 线程执行过程中，需调用此方法关闭线程
     */
    public final void exit() {
        if (Thread.currentThread() != this) {
            mWorkerHandler.sendEmptyMessage(ACTION_WORKER_THREAD_QUIT);
            return;
        }
        mReady = false;
        Looper.myLooper().quit();
        mWorkerHandler.release();
        mWorkerHandler = null;
    }

    /**
     * 确保引擎成功初始化
     */
    private RtcEngine ensureRtcEngineReadyLock() {
        try {
            if (mRtcEngine == null) {
                String appId = AgoraConstant.AGORA_APPID;
                if (TextUtils.isEmpty(appId)) {
                    throw new RuntimeException("Use your App ID, get your own ID at https://dashboard.agora.io/");
                }
                mRtcEngine = RtcEngine.create(mContext, appId, ModuleMgr.getRtcEnginMgr().getEngineHandler());
                mRtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_COMMUNICATION);
//            mRtcEngine.enableAudioVolumeIndication(200, 3); // 200 ms
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mRtcEngine;
    }

    /**
     * 工作线程处理类
     */
    private static final class WorkerThreadHandler extends Handler {
        private RtcWorkerThread mWorkerThread;

        WorkerThreadHandler(RtcWorkerThread thread) {
            this.mWorkerThread = thread;
        }

        public void release() {
            mWorkerThread = null;
        }

        @Override
        public void handleMessage(Message msg) {
            if (this.mWorkerThread == null) {
                return;
            }

            switch (msg.what) {
                case ACTION_WORKER_THREAD_QUIT:
                    mWorkerThread.exit();
                    break;
                case ACTION_WORKER_JOIN_CHANNEL:
                    mWorkerThread.joinChannel();
                    break;
                case ACTION_WORKER_LEAVE_CHANNEL:
                    String channel = (String) msg.obj;
                    mWorkerThread.leaveChannel(channel);
                    break;
                case ACTION_WORKER_CONFIG_ENGINE:
                    Object[] configData = (Object[]) msg.obj;
                    mWorkerThread.configVideoEngine((int) configData[0], (String) configData[1], (String) configData[2]);
                    break;
                case ACTION_WORKER_PREVIEW:
                    Object[] previewData = (Object[]) msg.obj;
                    mWorkerThread.preview((boolean) previewData[0], (SurfaceView) previewData[1], (int) previewData[2]);
                    break;
            }
        }
    }
}